using AssemblyVerifier;
using DynamicProxies;
using DynamicProxies.Tests.Types;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Reflection;
using System.Reflection.Emit;

namespace DynamicProxies.Tests
{
	[TestClass]
	public sealed class ByRefGenericArgumentTests : BaseTests
	{
		private bool afterInvocation;
		private bool beforeInvocation;

		protected override void OnSetup()
		{
			this.afterInvocation = false;
			this.beforeInvocation = false;
		}

		[TestMethod]
		public void ChangeArgumentValueBeforeInvocation()
		{
			try
			{
				this.beforeInvocation = true;
				ByRefGenericArgumentMethod method = Proxy.Create<ByRefGenericArgumentMethod>(
					new ProxyContext(AssemblyBuilderAccess.RunAndSave, true, true), this);
				var argument = "unchanged";
				method.ByRefArgument<string>(2, "value", ref argument);
				Assert.AreEqual("before", argument);
			}
			catch(VerificationException exception)
			{
				Utilities.WriteVerifcationErrors(exception.Errors);
				throw;
			}
		}

		[TestMethod]
		public void ChangeArgumentValueAfterInvocation()
		{
			this.afterInvocation = true;
			ByRefGenericArgumentMethod method = Proxy.Create<ByRefGenericArgumentMethod>(this);
			var argument = "unchanged";
			method.ByRefArgument<string>(2, "value", ref argument);
			Assert.AreEqual("after", argument);
		}

		protected override sealed bool OnBeforeMethodInvocation(MethodBase target, object[] arguments)
		{
			if(this.beforeInvocation)
			{
				arguments[arguments.Length - 1] = "before";
			}

			return true;
		}

		protected override sealed bool OnAfterMethodInvocation(MethodBase target, object[] arguments, ref object returnValue, Exception generatedException)
		{
			if(this.afterInvocation)
			{
				arguments[arguments.Length - 1] = "after";
			}

			return false;
		}
	}
}
